#include "stdafx.h"
#include "Menu.h"
#include <wingdi.h>
#include <tchar.h>
#include "Strsafe.h"
#include "resource.h"

static const int iIconX=4;
static const int iIconY=3;
static const int iItemY=22;
static const int iLPadding=32;
static const int iRPadding=20;

CMenu::CMenu()
{
	//item_cnt=0;
	//item_stack=NULL;

	button_cnt=0;
	button_ref=NULL;

	hFont=NULL;

	//iRecourse=0;
}

CMenu::~CMenu(void)
{
	if(button_ref) delete[] button_ref;

	while(!item_stack.empty())
	{
		delete item_stack.back();
		item_stack.pop_back();
	}

	//if(item_cnt>0)
	//{
	//	for(int t = 0; t<item_cnt; t++)
	//		if(item_stack[t]) delete item_stack[t];

	//	GlobalFree((HGLOBAL)item_stack);
	//}
}

BOOL CMenu::OnCreate(HWND hWindow) 
{
	hWnd=hWindow;

	LOGFONT m_lf={0};
    NONCLIENTMETRICS nm;
    nm.cbSize = sizeof(NONCLIENTMETRICS);
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, nm.cbSize,&nm, 0);
    // these fonts should auto destroy when the DLL unloads
    // create the normal menu item font
    m_lf = nm.lfMenuFont;
    hFont=CreateFontIndirect(&m_lf);

	//MENUBARINFO menuInfo = {sizeof(MENUBARINFO)};
	//if ( GetMenuBarInfo(hWnd, OBJID_MENU, 0, &menuInfo) );
	//int itemCount = ::GetMenuItemCount(menuInfo.hMenu);
	//for (int item = 1; item <= itemCount; item++)
	//{
	//	// make sure we do not change the state of the menu items as
	//	// we set the owner drawn style
	//	MENUITEMINFO	itemInfo;
	//
	//	memset(&itemInfo, 0, sizeof(MENUITEMINFO));
	//	itemInfo.cbSize = sizeof(MENUITEMINFO);
	//
	//	itemInfo.fMask = MIIM_STATE | MIIM_TYPE;
	//	/*VERIFY(*/::GetMenuItemInfo(menuInfo.hMenu,
	//			item, 
	//			TRUE,	   // by position
	//			&itemInfo)/*)*/;
	//	int itemID = ::GetMenuItemID(menuInfo.hMenu, item);
	//	if ((itemInfo.fType & MFT_SEPARATOR) == 0)
	//	{
	//		::ModifyMenu(menuInfo.hMenu,
	//				item, 
	//				itemInfo.fState | MF_BYPOSITION | MF_OWNERDRAW, 
	//				itemID,
	//				(LPCTSTR)item);
	//	}
	//	else
	//	{
	//		::ModifyMenu(menuInfo.hMenu,
	//				item, 
	//				MF_BYPOSITION | MF_OWNERDRAW | MF_SEPARATOR, 
	//				itemID,
	//				(LPCTSTR)item);
	//	}
	//}

	return 1;
}

void CMenu::OnInitMenuPopup(HMENU hMenu/*, UINT nIndex*/, BOOL bSysMenu)
{
	if(!hFont && bSysMenu)
	{
		LOGFONT m_lf={0};
		NONCLIENTMETRICS nm;
		nm.cbSize = sizeof(NONCLIENTMETRICS);
		SystemParametersInfo(SPI_GETNONCLIENTMETRICS, nm.cbSize,&nm, 0);
		// these fonts should auto destroy when the DLL unloads
		// create the normal menu item font
		m_lf = nm.lfMenuFont;
		hFont=CreateFontIndirect(&m_lf);
	}

	//static int iRecourse=0;
	//iRecourse++;

	if (hMenu != NULL)
	{
		MENUITEMINFO itemInfo;
		memset(&itemInfo, 0, sizeof(MENUITEMINFO));
		itemInfo.cbSize = sizeof(MENUITEMINFO);
		itemInfo.fMask = MIIM_STATE | MIIM_TYPE;

		int itemCount = ::GetMenuItemCount(hMenu);
		for (int item = 0; item < itemCount; item++)
		{
			UINT itemID = ::GetMenuItemID(hMenu, item);
			::GetMenuItemInfo(hMenu, item, TRUE, &itemInfo);
			if (itemID == (UINT) -1)
			{
				//HMENU subMenu=::GetSubMenu(hMenu,item);
				//if (subMenu) OnInitMenuPopup(subMenu);
				TCHAR szBuffer[_MAX_PATH];
				::GetMenuString(hMenu, item, szBuffer, _MAX_PATH, MF_BYPOSITION);
				MenuItem *p=AddItem(szBuffer, itemID, itemInfo.fType | (bSysMenu/*iRecourse==1*/ ? MFT_TITLE : 0), itemInfo.fState);
				::ModifyMenu(hMenu, item, itemInfo.fState | MF_BYPOSITION | MF_OWNERDRAW, (UINT) -1, (LPCTSTR)p);
			}
			else
			{
				TCHAR szBuffer[_MAX_PATH];
				::GetMenuString(hMenu, item, szBuffer, _MAX_PATH, MF_BYPOSITION);
				MenuItem *p=AddItem(szBuffer,itemID,itemInfo.fType,itemInfo.fState);

				if ((itemInfo.fType & MFT_SEPARATOR) == 0)
				{
					::ModifyMenu(hMenu,
							item, 
							itemInfo.fState | MF_BYPOSITION | MF_OWNERDRAW, 
							itemID,
							(LPCTSTR)p);
				}
				else
				{
					::ModifyMenu(hMenu,
							item, 
							MF_BYPOSITION | MF_OWNERDRAW | MF_SEPARATOR, 
							itemID,
							(LPCTSTR)p);
				}
			}
		}
	}

	//iRecourse--;
}

void CMenu::OnUnInitMenuPopup(HMENU _hMenu)
{
}

void CMenu::OnDestroy()
{
} 

// calculate menu line size
void CMenu::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpmis) 
{ 
	int w, h;
	MenuItem *itemInfo=(MenuItem*)lpmis->itemData;
	//UINT state = itemInfo->state;
	UINT type = itemInfo->type;

	// drawing a separator
	if (type & MFT_SEPARATOR)
	{
		lpmis->itemWidth = 0;
		lpmis->itemHeight = 3;
	}
	else
	{
		HDC hDC=CreateCompatibleDC(NULL);
		HFONT oldFont=(HFONT)SelectObject(hDC,hFont);

		if (itemInfo->cText[0]!='\0')
        {
			CRect rect(0,0,0,0);
			h = DrawText(hDC, itemInfo->cText, _tcslen(itemInfo->cText), &rect, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);
			//+3 makes at least three pixels space to the menu border
			w = rect.Width() + (type & MFT_TITLE ? 0 : iLPadding + iRPadding);
        }

		lpmis->itemWidth=w;
		lpmis->itemHeight=iItemY;

		SelectObject(hDC,oldFont);
		ReleaseDC(hWnd,hDC);
	}
}

// draw a menu line
void CMenu::OnDrawItem(LPDRAWITEMSTRUCT lpdis) 
{
	if(lpdis->CtlType!=ODT_MENU) return;

	CRect rectum(lpdis->rcItem);
	HDC mDC=CreateCompatibleDC (lpdis->hDC);
	HBITMAP m_bmp=CreateCompatibleBitmap (lpdis->hDC, rectum.Width(), rectum.Height());
	HBITMAP m_pOldBmp=(HBITMAP)SelectObject(mDC, m_bmp);

	// clean the whole line
	CBrush brush;
	brush.CreateSolidBrush(RGB(252,252,249));
	FillRect(mDC,&CRect(0,0,rectum.Width(),rectum.Height())/*lpdis->rcItem*/,brush);


	MenuItem *p=(MenuItem*)lpdis->itemData; 
	int x, y; 
 
	if(!(p->type & MFT_TITLE))
	{
		// Set the appropriate foreground and background colors. 
		TRIVERTEX vertices[2];

		vertices[0].x = 0;//lpdis->rcItem.left
		vertices[0].y = 0;//lpdis->rcItem.top;
		vertices[0].Red = 254<<8;
		vertices[0].Green = 254<<8;
		vertices[0].Blue = 251<<8;
		vertices[0].Alpha = 0xffff;

		vertices[1].x = /*lpdis->rcItem.left+*/24;
		vertices[1].y = rectum.Height();//lpdis->rcItem.bottom;
		vertices[1].Red = 196<<8;
		vertices[1].Green = 195<<8;
		vertices[1].Blue = 172<<8;
		vertices[1].Alpha = 0xffff;

		GRADIENT_RECT r;
		r.UpperLeft = 0;
		r.LowerRight = 1;

		GradientFill(mDC,vertices, 2, &r, 1, GRADIENT_FILL_RECT_H);
	}
 
	CRect rframe(0,0,rectum.Width(),rectum.Height());

	// draw selection line
	if (!(lpdis->itemState & (ODS_GRAYED|ODS_DISABLED)) && lpdis->itemState & ODS_SELECTED)
	{
		CBrush fbrush;
		brush.CreateSolidBrush(RGB(193,210,238));
		fbrush.CreateSolidBrush(GetSysColor(COLOR_MENUHILIGHT));
		FillRect(mDC,&rframe,brush);
		FrameRect(mDC,&rframe,fbrush);
	}

	// drawing a separator
	if (/*info.fType*/p->type & MFT_SEPARATOR)
	{
		RECT rline;
		brush.CreateSolidBrush(RGB(197,194,184));
		rline.left=rframe.left+iLPadding/*-1*/;
		rline.right=rframe.right/*+1*/;
		rline.bottom=rframe.bottom-1;
		rline.top=rframe.top+1;
		FillRect(mDC,&rline,brush);
    }
	else
	{
		SetBkMode(mDC,TRANSPARENT);
		int iconSY=0;
		// set grey text for disabled items
		if(lpdis->itemState & (ODS_GRAYED|ODS_DISABLED))
		{
			SetTextColor(mDC,RGB(192,192,192));
			iconSY=button_ref[0].icon;
		}
	 
		// Determine where to draw and leave space for a check mark. 
		x = 0; //lpdis->rcItem.left; 
		y = 0; //lpdis->rcItem.top;

		// draw checkbox if the item is checked
		if(lpdis->itemState & ODS_CHECKED)
		{
			RECT rect;
			brush.CreateSolidBrush(GetSysColor(COLOR_MENUHILIGHT));
			SetRect(&rect,x+iIconX-1,y+iIconY-1,x+iIconX+16+1,y+iIconY+16+1);
			FrameRect(mDC,&rect,brush);
		}

		// copy icon if there's one assigned
		for(int i=1; i<=button_cnt; i++)
		{
			if(button_ref[i].uID==lpdis->itemID)
			{
				HDC hdcMem = CreateCompatibleDC(mDC);
				HBITMAP oldBmp=(HBITMAP)SelectObject(hdcMem,hBitmap);
				TransparentBlt(mDC,x+iIconX,y+iIconY,button_ref[0].uID,button_ref[0].icon,
					hdcMem,button_ref[0].uID*button_ref[i].icon,iconSY,button_ref[0].uID,button_ref[0].icon,RGB(192,192,192));
				SelectObject(hdcMem,oldBmp);

				DeleteObject(hdcMem);
				break;
			}
		}

		if(p->type & MFT_TITLE)
		{
			HFONT oldFont = (HFONT)SelectObject(mDC, hFont);
			DrawText(mDC, p->cText, _tcslen(p->cText), &CRect(7,0,rectum.Width()-7,rectum.Height()), DT_LEFT | DT_SINGLELINE | DT_VCENTER);
			SelectObject(mDC,oldFont);
		}
		else
		{
			LPTSTR lpStrItem, lpStrAccel;
			SplitMenuText(p->cText.GetBuffer(),lpStrItem,lpStrAccel);
			// Select the font and draw the text.
			HFONT oldFont = (HFONT)SelectObject(mDC, hFont);
			CRect tRect(iLPadding,0,rectum.Width()-iLPadding-iIconX,rectum.Height());
			DrawText(mDC, lpStrItem, _tcslen(lpStrItem), &tRect, DT_LEFT | DT_SINGLELINE | DT_VCENTER);
			if(lpStrAccel) DrawText(mDC, lpStrAccel, _tcslen(lpStrAccel), &tRect, DT_RIGHT | DT_SINGLELINE | DT_VCENTER);
			SelectObject(mDC,oldFont);
		}
	}

	// copy back to original dc
	BitBlt (lpdis->hDC, rectum.left, rectum.top, rectum.Width(), rectum.Height(), mDC, 0/*rectum.left*/, 0/*rectum.top*/, SRCCOPY);
	// restore objects and flush
	SelectObject (mDC, m_pOldBmp);
	DeleteObject(mDC);
	DeleteObject(m_bmp);
}

void CMenu::OnNCPaint()
{
	HDC hdc=GetWindowDC(hWnd);
	//CBrush brush;

	//MENUBARINFO menuInfo = {sizeof(MENUBARINFO)};
	//if ( GetMenuBarInfo(hWnd, OBJID_MENU, 0, &menuInfo) )
	//{
	//	int i;
	//	MENUBARINFO submenuInfo = {sizeof(MENUBARINFO)};
	//	for(i=1; ; i++)
	//	{
	//		if(!GetMenuBarInfo(hWnd, OBJID_MENU, i, &submenuInfo))
	//			break;
	//	}
	//	COLORREF c1=GetSysColor(COLOR_ACTIVECAPTION);
	//	int r1=GetRValue(c1);
	//	int g1=GetGValue(c1);
	//	int b1=GetBValue(c1);
	//	COLORREF c2=GetSysColor(COLOR_GRADIENTACTIVECAPTION);
	//	r1=GetRValue(c2);
	//	g1=GetGValue(c2);
	//	b1=GetBValue(c2);

	//	RECT windowBounds;
	//	GetWindowRect(hWnd,&windowBounds);
	//	//RECT menuBounds(menuInfo.rcBar);
	//	menuInfo.rcBar.left-=windowBounds.left;
	//	menuInfo.rcBar.top-=windowBounds.top;
	//	menuInfo.rcBar.right-=windowBounds.left;
	//	menuInfo.rcBar.bottom-=windowBounds.top;
	//	//menuBounds.OffsetRect(-windowBounds.TopLeft());
	//	//brush.CreateSolidBrush(RGB(255,0,255));
	//	//FillRect(hdc,&menuInfo.rcBar,brush);
	//}

	// Paint into this DC
	ReleaseDC(hWnd, hdc);
}

void CMenu::LoadBitmap(LPCTSTR lpBitmapName)
{
	extern HINSTANCE hMainInstance;
	Image img, res;

	LoadResourceBmp(img,hMainInstance,lpBitmapName);

	res.Create(img.width,img.height*2,img.depth,img.palette);
	res.BitBlit(&img,0,0,img.width,img.height,0,0,Image::dir_normal);

	for(int y=0; y<img.height; y++)
	{
		u8 grey;
		for(int x=0; x<img.width; x++)
		{
			u32 p=img.GetPixelIndex(x,y);
			grey=((p&0xFF)+((p>>8)&0xFF)+((p>>16)&0xFF))/3;
			res.SetPixelAt(x,y+16,grey|(grey<<8)|(grey<<16));
		}
	}
	hBitmap.LoadBitmap(res);
}

void CMenu::SetButtonRef(LPBUTTONREF ref, int count)
{
	if(button_ref) delete[] button_ref;
	button_ref=new BUTTON_REF[count];

	memcpy(button_ref,ref,sizeof(BUTTON_REF)*count);
	button_cnt=count;
}

CMenu::MenuItem* CMenu::AddItem(LPCTSTR string, const int cmd, UINT type, UINT state)
{
	//if (item_cnt == 0)
	//	item_stack = (MenuItem **) GlobalAlloc(GPTR, sizeof(MenuItem));
	//else
	//	item_stack = (MenuItem **) GlobalReAlloc((HGLOBAL) item_stack, sizeof(MenuItem) * (item_cnt + 1), GMEM_MOVEABLE|GMEM_ZEROINIT);

	//ASSERT(pSpawnItem)

	//MenuItem *p=new MenuItem;
	//item_stack[item_cnt] = p;

	MenuItem *p=new MenuItem;
	p->type=type;
	p->state=state;
	p->cText=string;
	p->iCmd=cmd;
	item_stack.push_back(p);

	//if (cmd >= 0) p->iImageIdx = FindImageItem(cmd);
	//else p->iImageIdx = cmd;
	//item_cnt++;

	return p;
}

void CMenu::SplitMenuText(LPTSTR menuItemText, LPTSTR &menuText, LPTSTR &acceleratorText)
{
	menuText=menuItemText;

    for (int tabIndex = 0 ; menuItemText[tabIndex]!=NULL ; tabIndex++)
    {
        if (menuItemText[tabIndex] == _T('\t'))
        {
			menuItemText[tabIndex]=NULL;
			acceleratorText=&menuItemText[tabIndex+1];
			return;
        }
    }

	acceleratorText=NULL;
}

